/*
 * SdlVideoWindow.cpp
 *
 *  Created on: 2016年5月17日
 *      Author: terry
 */

#include "SdlVideoWindow.h"
#include "TRandom.h"
#include "CLog.h"
#include "FfmpegUtil.h"


namespace av
{


SdlVideoWindow::SdlVideoWindow():
		m_window(),
		m_winID(),
		m_parentWnd(),
		m_state(STATE_STOPPED),
		m_ratioX(),
		m_ratioY(),
		m_renderer()
{
	m_eventManager = sdl::EventManager::create();
}

SdlVideoWindow::~SdlVideoWindow()
{
	sdl::EventManager::destroy(m_eventManager);
}

int SdlVideoWindow::open(void* hwnd)
{
	CLog::debug("SdlVideoWindow::open %x\n", hwnd);

	m_parentWnd = hwnd;

	if (hwnd)
	{
		m_window = SDL_CreateWindowFrom(hwnd);
	}
	else
	{
		int flags = SDL_WINDOW_SHOWN;
		m_window = SDL_CreateWindow("video window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
			640, 480, flags);
	}

	if (!m_window)
	{
		CLog::error("failed to create window.\n");

		int flags = SDL_WINDOW_SHOWN;
		m_window = SDL_CreateWindow("video window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
			640, 480, flags);
		if (!m_window)
		{
			return ENODEV;
		}
	}

	//putIntoWindow(m_parentWnd);

	m_winID = SDL_GetWindowID(m_window);
	m_eventManager->add(m_winID, this);

	m_renderer = SDL_CreateRenderer(m_window, -1, 0);

	return 0;
}

void SdlVideoWindow::close()
{
	m_eventManager->remove(m_winID);

	if (m_renderer)
	{
		SDL_DestroyRenderer(m_renderer);
		m_renderer = NULL;
	}

	if (m_window)
	{
		SDL_DestroyWindow(m_window);
		m_window = NULL;
	}

	m_presenter.reset();
	m_backImage.reset();
}

bool SdlVideoWindow::isOpen()
{
	return (m_window != NULL);
}

void SdlVideoWindow::setVideoWnd(void* hwnd)
{
    //putIntoWindow(hwnd);

    m_parentWnd = hwnd;
}

void SdlVideoWindow::setState(StreamState state)
{
    comn::AutoCritSec lock(m_cs);
    m_state = state;
}

bool SdlVideoWindow::draw(AVFrame* frame)
{
	if (m_state == STATE_STOPPED)
	{
		return false;
	}

    {
        comn::AutoCritSec lock(m_cs);
		m_backFrame = ffmpeg::makeFrame(frame);
    }

    invalidate();

	return true;
}

bool SdlVideoWindow::isFullscreen()
{
	return false;
}

bool SdlVideoWindow::setFullscreen(bool full)
{
	//todo
	return false;
}

bool SdlVideoWindow::setRatio(int width, int height)
{
	comn::AutoCritSec lock(m_cs);

	m_ratioX = width;
	m_ratioY = height;

	return true;
}

void SdlVideoWindow::getRatio(int& width, int& height)
{
	width = m_ratioX;
	height = m_ratioY;
}

bool SdlVideoWindow::setBackImage(const char* filepath)
{
    SDL_Surface* pSurface = SDL_LoadBMP(filepath);
    if (!pSurface)
    {
        return false;
    }

    m_backImage.reset(pSurface);

    return true;
}

void SdlVideoWindow::flush()
{
    {
        comn::AutoCritSec lock(m_cs);
        m_backFrame.reset();
        m_curFrame.reset();
    }

    drawBackground(true);
}

void SdlVideoWindow::setVisible(bool visible)
{
	if (visible)
	{
		SDL_ShowWindow(m_window);
	}
	else
	{
		SDL_HideWindow(m_window);
	}
}

void SdlVideoWindow::handleEvent(SDL_Event& event)
{
    if (event.type == SDL_WINDOWEVENT)
    {
        //CLog::debug("sdl window event: %d\n", event.window.event);
        if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
        {
            updateRender();
            drawFrame();
        }
        else if (event.window.event == SDL_WINDOWEVENT_SHOWN)
        {
        }
		else if (event.window.event == SDL_WINDOWEVENT_EXPOSED)
		{
			drawFrame();
		}
        else if (event.window.event == SDL_WINDOWEVENT_RESIZED)
        {
            updateRender();
            drawFrame();
        }
    }
    else if (event.type == USEREVENT_DRAW_FRAME)
    {
        drawFrame();
    }
}

void SdlVideoWindow::drawFrame()
{
    fetchFrame();

    if (m_curFrame)
    {
        //if (resizeToWindow(m_parentWnd))
        {
            //updateRender();
        }

        drawFrame(m_curFrame.get());
    }
    else
    {
        drawBackground(true);
    }
}

void SdlVideoWindow::drawFrame(AVFrame* pFrame)
{
	SDL_Rect rcWin = {0, 0, 320, 240};
	SDL_GetWindowSize(m_window, &rcWin.w, &rcWin.h);

	if (SDL_RectEmpty(&rcWin))
	{
		return;
	}

	SDL_RenderClear(m_renderer);

	m_presenter.draw(m_renderer, pFrame, m_ratioX, m_ratioY);

	SDL_RenderPresent(m_renderer);
}


void SdlVideoWindow::drawBackground(bool drawImage)
{
    SDL_Window* pWindow = m_window;
    SDL_Renderer* pRender = m_renderer;
    //if (m_fullscreen && m_pScreenWindow)
    //{
    //    pWindow = m_pScreenWindow;
    //    pRender = m_screenRenderer;
    //}

    m_backImage.update(pRender);

    if (!pWindow || !pRender)
    {
        return;
    }

    SDL_Rect rcWin = {0, 0, 320, 240};
    SDL_GetWindowSize(pWindow, &rcWin.w, &rcWin.h);

    if (SDL_RectEmpty(&rcWin))
    {
        return;
    }

    SDL_SetRenderDrawColor(pRender, 0, 0, 0, 0);
    SDL_RenderClear(pRender);

    SDL_Rect rcImage = { 0, 0, 0, 0 };
    m_backImage.getSize(rcImage.w, rcImage.h);
    rcImage.x = rcWin.x + (rcWin.w - rcImage.w)/2;
    rcImage.y = rcWin.y + (rcWin.h - rcImage.h)/2;

    SDL_RenderCopy(pRender, m_backImage.getTexture(), NULL, &rcImage);

    SDL_RenderPresent(pRender);

}

/*
void SdlVideoWindow::putIntoWindow(void* hwnd)
{
	SDL_SysWMinfo info;
	SDL_VERSION(&info.version);
	SDL_GetWindowWMInfo(m_window, &info);

	SetParent(info.info.win.window, (HWND)hwnd);

    RECT rect;
    GetClientRect((HWND)hwnd, &rect);
    //MoveWindow(info.info.win.window, rect.left, rect.top,
    //    rect.right - rect.left, rect.bottom - rect.top, FALSE);

    MoveWindow(info.info.win.window, rect.left, rect.top,
        320, 240, FALSE);
}

bool SdlVideoWindow::resizeToWindow(void* hwnd)
{
    bool changed = false;
    RECT rect;
    GetClientRect((HWND)hwnd, &rect);

    int width = 0;
    int height = 0;
    SDL_GetWindowSize(m_window, &width, &height);

    if ((width != (rect.right - rect.left)) ||
    		(height != (rect.bottom - rect.top)))
    {
        SDL_SysWMinfo info;
        SDL_VERSION(&info.version);
        SDL_GetWindowWMInfo(m_window, &info);
        MoveWindow(info.info.win.window, rect.left, rect.top,
            rect.right - rect.left, rect.bottom - rect.top, FALSE);

        changed = true;
    }
    return changed;
}
*/

void SdlVideoWindow::updateRender()
{
    SDL_DestroyRenderer(m_renderer);
    m_renderer = NULL;

    m_renderer = SDL_CreateRenderer(m_window, -1, 0);
}

void SdlVideoWindow::invalidate()
{
    SDL_Event event;
    memset(&event, 0, sizeof(event));
    event.type = USEREVENT_DRAW_FRAME;
    event.window.windowID = m_winID;

    SDL_PushEvent(&event);
}

void SdlVideoWindow::fetchFrame()
{
    comn::AutoCritSec lock(m_cs);
    if (m_backFrame)
    {
        m_curFrame = m_backFrame;
        m_backFrame.reset();
    }
}



} /* namespace av */
